package com.acme.multithreadinglab.factorizer;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class CachedComputable3<A,V>  implements Computable<A, V>{
	private final Computable<A, V> c;
	private final ConcurrentHashMap<A,Future<V>> cache = new ConcurrentHashMap<A, Future<V>>();
	
	public CachedComputable3(Computable<A, V> c) {
		this.c = c;
	}

	public V compute(final A arg) throws InterruptedException {
		Future<V> result = cache.get(arg);
		if (result == null) {
			Callable<V> task = new Callable<V>() {
				public V call() throws Exception {
					return c.compute(arg);
				}
			};
			FutureTask<V> ft = new FutureTask<>(task);
			if ((result = cache.putIfAbsent(arg, ft)) == null){
				ft.run();
				result = ft;
			}
		}
		try {
			return result.get();
		} catch (ExecutionException e) {
			throw new RuntimeException(e);
		}
	}

}
